package com.twu.biblioteca;

import com.twu.biblioteca.menu.*;
import com.twu.biblioteca.model.Book;
import com.twu.biblioteca.model.LibraryCollection;
import com.twu.biblioteca.model.Movie;
import com.twu.biblioteca.model.User;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class BibliotecaApp {

    private static final String welcomeMessage = "Welcome to Biblioteca";

    //private static BibliotecaApp INSTANCE;

    private User currentUser;
    private List<User> registeredUsers;

    private LibraryCollection<Book> bookCollection = new LibraryCollection<Book>();
    private LibraryCollection<Movie> movieCollection = new LibraryCollection<Movie>();

    private Menu mainMenu;

    private InputStream inputStream;
    private PrintStream outputStream;

    private static final List<Book> testBooks = Arrays.asList(
            new Book("The Agile Samuri"),
            new Book("A Song of Ice and Fire: A Game of Thrones"),
            new Book("Mr Men: Mr Bump"),
            new Book("The Hobbit"));

    private static final List<Movie> testMovies = Arrays.asList(
            new Movie("Gattaca", "Andrew Niccol", 1997, 0));


    public static void main(String[] args) {
        BibliotecaApp appInstance = build();
        appInstance.run();
    }

    public static BibliotecaApp build() {
        return build(testBooks, testMovies);
    }

    public static BibliotecaApp build(List<Book> bookCatalog, List<Movie> movieCatalog) {
        return build(bookCatalog, movieCatalog,
                Arrays.asList(new ViewBooksMenuItem(),
                        new ReserveBookMenuItem(),
                        new ViewMoviesMenuItem(),
                        new LoginMenuItem(),
                        new CheckMembershipMenuItem(),
                        new QuitMenuItem()));
    }

    public static BibliotecaApp build(List<Book> bookCatalog, List<Movie> movieCatalog,  List<IMenuItem> menuItems) {
        return build(bookCatalog, movieCatalog, generateDefaultUsers(),menuItems);
    }

    private static List<User> generateDefaultUsers() {
        ArrayList<User> userList = new ArrayList<User>(15);

        User user = new User("111-1111", "password1", "1@some_email.com", "123456789");
        userList.add(user);
        for (int i = 1; i < 15; i++) {
            user = new User(User.getNextUsername(user), "password" + (i + 1), i + "@some_email.com", "12345678");
            userList.add(user);
        }
        return userList;
    }

    public static BibliotecaApp build(List<Book> bookCatalog, List<Movie> movieCatalog, List<User> users, List<IMenuItem> menuItems) {
        return build(bookCatalog, movieCatalog, users, menuItems, System.in, System.out);
    }


    public static BibliotecaApp build(List<Book> bookCatalog, List<Movie> movieCatalog,
                                      List<User> users, List<IMenuItem> menuItems,
                                      InputStream inputStream, PrintStream outputStream) {
        BibliotecaApp instance = new BibliotecaApp();
        for (Book book : bookCatalog) {
            instance.getBookCollection().addItemToCollection(book);
        }
        for (Movie movie : movieCatalog) {
            instance.getMovieCollection().addItemToCollection(movie);
        }
        instance.registeredUsers = new ArrayList<User>();
        instance.registeredUsers.addAll(users);

        instance.setMenu(Menu.build(menuItems));
        instance.inputStream = inputStream;
        instance.outputStream = outputStream;
        return instance;
    }

    public void setMenu(Menu mainMenu) {
        this.mainMenu = mainMenu;
    }

    public void run() {
        outputStream.println(getWelcomeMessage());
        IMenuItem current = null;
        while (!(current instanceof QuitMenuItem)) {
            printMenu();
            int selectedIndex = getSelectedOption();

            current = mainMenu.getItem(selectedIndex - 1);
            if (current == null) {
                outputStream.println("Select a valid option!!");
            } else {
                current.doAction(this);
            }
        }
    }

    public void printMenu() {
        outputStream.println("\n----- Main Menu -----");
        outputStream.println(mainMenu.getMenuString(this));
    }

    public PrintStream getOutputStream() {
        return outputStream;
    }

    public void setOutputStream(PrintStream outputStream) {
        this.outputStream = outputStream;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(ByteArrayInputStream inputStream) {
        this.inputStream = inputStream;
    }

    public String getWelcomeMessage() {
        return welcomeMessage;
    }

    public LibraryCollection<Book> getBookCollection() {
        return bookCollection;
    }

    public LibraryCollection<Movie> getMovieCollection() {
        return movieCollection;
    }

    public int getSelectedOption() {
        outputStream.print("Please Select a Menu Option: ");
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            int selection = Integer.parseInt(reader.readLine());

            if (selection <= mainMenu.getSize() && selection > -1) {
                return selection;
            } else {
                return -1;
            }


        } catch (NumberFormatException e) {
            return -1;
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
    }

    public User getCurrentUser() {
        return currentUser;
    }

    public boolean logInUser(String username, String password) {

        for(User nextRegisteredUser: registeredUsers){
            if (nextRegisteredUser.getUsername().equals(username)) {
                if (nextRegisteredUser.getPassword().equals(password)) {
                    currentUser = nextRegisteredUser;
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }

    public void logout() {
        currentUser = null;
    }
}